package com.bwton.msx.ccb.utils;

import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.text.TextUtils;


import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.sensetime.ssidmobile.sdk.liveness.constants.STMotion;
import com.sensetime.ssidmobile.sdk.liveness.model.config.DefakeConfig;
import com.sensetime.ssidmobile.sdk.liveness.model.config.LivenessConfig;
import com.sensetime.ssidmobile.sdk.liveness.model.config.MotionConfig;
import com.sensetime.ssidmobile.sdk.liveness.model.config.QualityConfig;
import com.sensetime.ssidmobile.sdk.liveness.model.config.SilentConfig;


import java.util.ArrayList;
import java.util.List;

/**
 * Created on 2017/03/09 13:39.
 *
 * @author Han Xu
 */
public final class PreferenceUtil {

    private static final String KEY_COMPARE_MODE_VOICE = "key_compare_mode_voice";
    private static final String KEY_INTERACTIVE_LIVENESS_VOICE = "key_interactive_liveness_voice";
    private static final String KEY_DIFFICULTY = "key_difficulty";
    private static final String KEY_RANDOM_SEQUENCE = "key_random_sequence";
    private static final String KEY_SAVE_INTERACTIVE_IMAGE = "key_save_interactive_image";
    private static final String KEY_SHOW_CROP_PREVIEW = "key_show_crop_preview";
    private static final String KEY_SAVE_SILENT_IMAGE = "key_save_silent_image";
    private static final String KEY_SEQUENCE = "key_sequence";
    private static final String KEY_TIMEOUT = "key_timeout";
    private static final String KEY_READY_TIMEOUT = "key_ready_timeout";
    private static final String KEY_LICENSE_PATH = "key_license_path";
    private static final String KEY_VERIFY_SOURCE = "key_verify_source";
    private static final String KEY_MOTION_TIMEOUT = "key_motion_timeout";
    private static final String KEY_THRESHOLD_CONFIG = "key_threshold_config";
    private static final String KEY_SAVE_FRAME_IMAGE = "key_save_frame";
    private static final String KEY_IS_ROI = "key_is_roi";
    private static final String KEY_SAVE_LIVENESS_IMAGE = "key_save_liveness";
    private static final String KEY_LIVENESS_THRESHOLD_CONFIG = "KEY_LIVENESS_THRESHOLD_CONFIG";
    private static final String KEY_SILENT_THRESHOLD_CONFIG = "KEY_SILENT_THRESHOLD_CONFIG";
    private static final String KEY_THRESHOLD_DEFAKE_CONFIG = "KEY_THRESHOLD_DEFAKE_CONFIG";
    private static final String KEY_COLOR_THRESHOLD_CONFIG = "KEY_COLOR_THRESHOLD_CONFIG";

    private static final char SEPARATOR = ';';

    private static final String DEFAULT_SEQUENCE = String.valueOf(STMotion.BLINK)
            + SEPARATOR
            + STMotion.MOUTH
            + SEPARATOR
            + STMotion.NOD
            + SEPARATOR
            + STMotion.YAW;

    private static SharedPreferences mPreferences = null;

    public static void init(Context context) {
        mPreferences = PreferenceManager.getDefaultSharedPreferences(context);
    }

    public static boolean isCompareModeVoiceOn() {
        return mPreferences.getBoolean(KEY_COMPARE_MODE_VOICE, true);
    }

    public static boolean isInteractiveLivenessVoiceOn() {
        return mPreferences.getBoolean(KEY_INTERACTIVE_LIVENESS_VOICE, true);
    }

    public static void setIsCompareModeVoiceOn(boolean isVoiceOn) {
        mPreferences.edit().putBoolean(KEY_COMPARE_MODE_VOICE, isVoiceOn).apply();
    }

    public static boolean isRandomSequenceOn() {
        return mPreferences.getBoolean(KEY_RANDOM_SEQUENCE, true);
    }

    public static void setIsRandomSequenceOn(boolean isOn) {
        mPreferences.edit().putBoolean(KEY_RANDOM_SEQUENCE, isOn).apply();
    }

    public static void setIsInteractiveLivenessVoiceOn(boolean isOn) {
        mPreferences.edit().putBoolean(KEY_INTERACTIVE_LIVENESS_VOICE, isOn).apply();
    }


    public static boolean isRoi() {
        return mPreferences.getBoolean(KEY_IS_ROI, true);
    }

    public static void setIsRoi(boolean isOpen) {
        mPreferences.edit().putBoolean(KEY_IS_ROI, isOpen).apply();
    }

    public static boolean isSaveFrame() {
        return mPreferences.getBoolean(KEY_SAVE_FRAME_IMAGE, true);
    }

    public static void setSaveFrame(boolean isSave) {
        mPreferences.edit().putBoolean(KEY_SAVE_FRAME_IMAGE, isSave).apply();
    }

    public static boolean isSaveLiveness() {
        return mPreferences.getBoolean(KEY_SAVE_LIVENESS_IMAGE, false);
    }

    public static void setSaveLiveness(boolean isSave) {
        mPreferences.edit().putBoolean(KEY_SAVE_LIVENESS_IMAGE, isSave).apply();
    }

    public static boolean isLoop() {
        return mPreferences.getBoolean(KEY_SAVE_INTERACTIVE_IMAGE, false);
    }

    public static boolean isShowCropPreview() {
        return mPreferences.getBoolean(KEY_SHOW_CROP_PREVIEW, false);
    }

    public static void setShowCropPreview(boolean isShow) {
        mPreferences.edit().putBoolean(KEY_SHOW_CROP_PREVIEW, isShow).apply();
    }

    public static boolean isSaveSilentImage() {
        return mPreferences.getBoolean(KEY_SAVE_SILENT_IMAGE, false);
    }

    public static void setIsLoop(boolean isEnable) {
        mPreferences.edit().putBoolean(KEY_SAVE_INTERACTIVE_IMAGE, isEnable).apply();
    }

    public static long getMotionTimeOutMillis() {
        return mPreferences.getLong(KEY_MOTION_TIMEOUT, new MotionConfig.Builder().build().motionTimeoutMillis);
    }

    public static void setMotionTimeOutMillis(long motionTimeoutMillis) {
        mPreferences.edit().putLong(KEY_MOTION_TIMEOUT, motionTimeoutMillis).apply();
    }

    public static long getMotionReadyTimeOutMillis() {
        return mPreferences.getLong(KEY_TIMEOUT, new MotionConfig.Builder().build().readyTimeoutMillis);
    }

    public static void setMotionReadyTimeOutMillis(long timeout) {
        mPreferences.edit().putLong(KEY_TIMEOUT, timeout).apply();
    }

    public static void saveVerifySourcePath(String verifySourcePath) {
        mPreferences.edit().putString(KEY_VERIFY_SOURCE, verifySourcePath).apply();
    }

    public static String getVerifySourcePath() {
        return mPreferences.getString(KEY_VERIFY_SOURCE, "");
    }

    public static void saveLicensePath(String licensePath) {
        mPreferences.edit().putString(KEY_LICENSE_PATH, licensePath).apply();
    }

    public static String getLicensePath() {
        return mPreferences.getString(KEY_LICENSE_PATH, "");
    }

    public static void setIsSaveSilentImageEnable(boolean isEnable) {
        mPreferences.edit().putBoolean(KEY_SAVE_SILENT_IMAGE, isEnable).apply();
    }

    public static int[] getSequence() {
        return splitWorker(mPreferences.getString(KEY_SEQUENCE, DEFAULT_SEQUENCE), SEPARATOR, false);
    }

    public static void setSequence(int[] sequence) {
        mPreferences.edit().putString(KEY_SEQUENCE, join(sequence, SEPARATOR, 0, sequence.length)).apply();
    }

    public static List<Integer> getSequenceList() {
        return splitStringWorker(mPreferences.getString(KEY_SEQUENCE, DEFAULT_SEQUENCE), SEPARATOR, false);
    }

    public static QualityConfig getQualityConfig() {
        String thresholdConfigJson = mPreferences.getString(KEY_THRESHOLD_CONFIG, "");
        QualityConfig qualityConfig;
        if (TextUtils.isEmpty(thresholdConfigJson)) {
            qualityConfig = new QualityConfig.Builder().build();
        } else {
            try {
                qualityConfig = new Gson().fromJson(thresholdConfigJson, QualityConfig.class);
            } catch (JsonSyntaxException e) {
                e.printStackTrace();
                qualityConfig = new QualityConfig.Builder().build();
            }
        }
        return qualityConfig;
    }

    public static void setQualityConfig(QualityConfig qualityConfig) {
        mPreferences.edit().putString(KEY_THRESHOLD_CONFIG, new Gson().toJson(qualityConfig)).apply();
    }

    public static LivenessConfig qetLivenessConfig() {
        String livenessConfigJson = mPreferences.getString(KEY_LIVENESS_THRESHOLD_CONFIG, "");
        LivenessConfig qualityConfig;
        if (TextUtils.isEmpty(livenessConfigJson)) {
            qualityConfig = new LivenessConfig.Builder().build();
        } else {
            try {
                qualityConfig = new Gson().fromJson(livenessConfigJson, LivenessConfig.class);
            } catch (JsonSyntaxException e) {
                e.printStackTrace();
                qualityConfig = new LivenessConfig.Builder().build();
            }
        }
        return qualityConfig;
    }

    public static void setLivenessConfig(LivenessConfig livenessConfig) {
        mPreferences.edit().putString(KEY_LIVENESS_THRESHOLD_CONFIG, new Gson().toJson(livenessConfig)).apply();
    }

    public static long getTimeOutMillis() {
        return mPreferences.getLong(KEY_TIMEOUT, new MotionConfig.Builder().build().readyTimeoutMillis);
    }

    public static void setTimeOutMillis(long timeout) {
        mPreferences.edit().putLong(KEY_TIMEOUT, timeout).apply();
    }

    public static long getReadyTimeOutMillis() {
        return mPreferences.getLong(KEY_READY_TIMEOUT, new MotionConfig.Builder().build().readyTimeoutMillis);
    }

    public static void setReadyTimeOutMillis(long timeout) {
        mPreferences.edit().putLong(KEY_READY_TIMEOUT, timeout).apply();
    }

    public static SilentConfig qetSilentConfig() {
        String livenessConfigJson = mPreferences.getString(KEY_SILENT_THRESHOLD_CONFIG, "");
        SilentConfig silentConfig;
        if (TextUtils.isEmpty(livenessConfigJson)) {
            silentConfig = new SilentConfig.Builder().build();
        } else {
            try {
                silentConfig = new Gson().fromJson(livenessConfigJson, SilentConfig.class);
            } catch (JsonSyntaxException e) {
                e.printStackTrace();
                silentConfig = new SilentConfig.Builder().build();
            }
        }
        return silentConfig;
    }

    public static void setSilentConfig(SilentConfig silentConfig) {
        mPreferences.edit().putString(KEY_SILENT_THRESHOLD_CONFIG, new Gson().toJson(silentConfig)).apply();
    }

    public static DefakeConfig getDefakeConfig() {
        String thresholdConfigJson = mPreferences.getString(KEY_THRESHOLD_DEFAKE_CONFIG, "");
        DefakeConfig defakeConfig;
        if (TextUtils.isEmpty(thresholdConfigJson)) {
            defakeConfig = new DefakeConfig.Builder().build();
        } else {
            try {
                defakeConfig = new Gson().fromJson(thresholdConfigJson, DefakeConfig.class);
            } catch (JsonSyntaxException e) {
                e.printStackTrace();
                defakeConfig = new DefakeConfig.Builder().build();
            }
        }
        return defakeConfig;
    }

    public static void setDefakeConfig(DefakeConfig defakeConfig) {
        mPreferences.edit().putString(KEY_THRESHOLD_DEFAKE_CONFIG, new Gson().toJson(defakeConfig)).apply();
    }


    /**
     * Save new selected motion sequence.
     *
     * @param sequence STMotion sequence.
     */
    public static void setSequenceList(List<Integer> sequence) {
        mPreferences.edit()
                .putString(KEY_SEQUENCE,
                        join(convertIntegerListToArray(sequence), SEPARATOR, 0, sequence.size()))
                .apply();
    }

    private static String join(int[] array, char separator, int startIndex, int endIndex) {
        if (array == null) {
            return null;
        }
        int bufSize = (endIndex - startIndex);
        if (bufSize <= 0) {
            return "";
        }

        bufSize *= ((String.valueOf(array[startIndex]).length()) + 1);
        StringBuilder buf = new StringBuilder(bufSize);

        for (int i = startIndex; i < endIndex; i++) {
            if (i > startIndex) {
                buf.append(separator);
            }
            buf.append(array[i]);
        }
        return buf.toString();
    }

    private static int[] splitWorker(String str, char separatorChar, boolean presserveAllTokens) {
        if (str == null) {
            return null;
        }
        int len = str.length();
        if (len == 0) {
            return new int[0];
        }
        List<Integer> list = new ArrayList<>();
        int i = 0;
        int start = 0;
        boolean match = false;
        boolean lastMatch = false;
        while (i < len) {
            if (str.charAt(i) == separatorChar) {
                if (match || presserveAllTokens) {
                    list.add(Integer.parseInt(str.substring(start, i)));
                    match = false;
                    lastMatch = true;
                }
                start = ++i;
                continue;
            }
            lastMatch = false;
            match = true;
            i++;
        }
        if (match || (presserveAllTokens && lastMatch)) {
            list.add(Integer.parseInt(str.substring(start, i)));
        }
        int[] result = new int[list.size()];
        for (int index = 0; index < list.size(); index++) {
            result[index] = list.get(index);
        }
        return result;
    }

    private static List<Integer> splitStringWorker(String str, char separatorChar, boolean presserveAllTokens) {
        if (str == null) {
            return null;
        }
        int len = str.length();
        if (len == 0) {
            return new ArrayList<>();
        }
        List<Integer> list = new ArrayList<>();
        int i = 0;
        int start = 0;
        boolean match = false;
        boolean lastMatch = false;
        while (i < len) {
            if (str.charAt(i) == separatorChar) {
                if (match || presserveAllTokens) {
                    list.add(Integer.parseInt(str.substring(start, i)));
                    match = false;
                    lastMatch = true;
                }
                start = ++i;
                continue;
            }
            lastMatch = false;
            match = true;
            i++;
        }
        if (match || (presserveAllTokens && lastMatch)) {
            list.add(Integer.parseInt(str.substring(start, i)));
        }
        return list;
    }

    public static int[] convertIntegerListToArray(final List<Integer> integerList) {
        if (integerList.isEmpty()) {
            return new int[0];
        }

        int[] array = new int[integerList.size()];

        for (int index = 0; index < integerList.size(); index++) {
            array[index] = integerList.get(index);
        }

        return array;
    }
}